﻿using System;
using System.Threading;
using NUnit.Framework;

namespace dnAnalytics.Tests.Random
{
    public abstract class RandomTests
    {
        private const int _n = 10000;
        private readonly Type _randomType;

        protected RandomTests(Type randomType)
        {
            _randomType = randomType;
        }

        [Test]
        public void Sample()
        {
            System.Random random = (System.Random) Activator.CreateInstance(_randomType, new object[] {false});
            double sum = 0;
            for (int i = 0; i < _n; i++)
            {
                double next = random.NextDouble();
                sum += next;
                Assert.That(next, Is.AtLeast(0));
                Assert.That(next, Is.AtMost(1));
            }
            //make sure are within 10% of the expected sum.
            Assert.That(sum, Is.AtLeast(_n/2.0 - .05*_n));
            Assert.That(sum, Is.AtMost(_n/2.0 + .05*_n));
            if (random is IDisposable)
            {
                ((IDisposable) random).Dispose();
            }
        }

        [Test]
        public void ThreadSafeSample()
        {
            System.Random random = (System.Random) Activator.CreateInstance(_randomType, new object[] {true});

            Thread t1 = new Thread(runTest);
            Thread t2 = new Thread(runTest);
            t1.Start(random);
            t2.Start(random);
            t1.Join();
            t2.Join();
        }

        public void runTest(object random)
        {
            System.Random rng = (System.Random) random;
            for (int i = 0; i < _n; i++)
            {
                double next = rng.NextDouble();
                Assert.That(next, Is.AtLeast(0));
                Assert.That(next, Is.AtMost(1));
            }
        }
    }
}